[Feat] 트래킹 안내난이도 후기 등록 추가#122
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughAdds end-to-end course difficulty feedback: new enum and status constants, DTOs, JPA entity, repository, DB migration, service logic with duplicate handling, controller endpoint and docs, left-join query adjustments, and comprehensive unit tests. ChangesCourse Difficulty Feedback Feature
Sequence DiagramsequenceDiagram
participant Client
participant HikingRecordController
participant HikingRecordService
participant CourseDifficultyFeedbackRepository
participant Database
Client->>HikingRecordController: POST /{hikingRecordId}/difficulty-feedback (comparison)
HikingRecordController->>HikingRecordService: createCourseDifficultyFeedback(userId, hikingRecordId, request)
HikingRecordService->>HikingRecordService: validate onboarding, membership, course presence
HikingRecordService->>CourseDifficultyFeedbackRepository: existsByHikingRecord_Id(hikingRecordId)
CourseDifficultyFeedbackRepository->>Database: SELECT EXISTS(...)
alt not exists
HikingRecordService->>CourseDifficultyFeedbackRepository: saveAndFlush(courseDifficultyFeedback)
CourseDifficultyFeedbackRepository->>Database: INSERT course_difficulty_feedbacks ...
Database-->>CourseDifficultyFeedbackRepository: commit
CourseDifficultyFeedbackRepository-->>HikingRecordService: saved entity
else exists or unique-constraint violation
CourseDifficultyFeedbackRepository-->>HikingRecordService: DataIntegrityViolationException / exists true
end
HikingRecordService-->>HikingRecordController: CourseDifficultyFeedbackResponse
HikingRecordController-->>Client: 201 Created (ApiResponse.success)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
Suggested reviewers
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
src/test/java/com/semosan/api/domain/hiking/service/HikingRecordServiceTest.java (1)
151-171: ⚡ Quick winAdd a non-duplicate integrity-violation test case.
Line 160–170 currently proves duplicate mapping for one
DataIntegrityViolationExceptionpath only. Add a companion test for a non-unique integrity error (e.g., FK/NOT NULL) and assert it is not converted toCOURSE_DIFFICULTY_FEEDBACK_ALREADY_EXISTS, so unrelated DB failures are not masked.Suggested test addition
+ `@Test` + void createCourseDifficultyFeedbackDoesNotMapNonDuplicateIntegrityViolation() throws Exception { + User user = user(1L); + HikingRecord hikingRecord = hikingRecord(10L, course(mountain(20L, "관악산"), 30L, "과천향교 출발 코스")); + + when(userReader.findCompletedOnboardingUserById(1L)).thenReturn(user); + when(hikingRecordRepository.findById(10L)).thenReturn(Optional.of(hikingRecord)); + when(hikingMemberRepository.existsByHikingRecordAndUser(hikingRecord, user)).thenReturn(true); + when(courseDifficultyFeedbackRepository.existsByHikingRecord_Id(10L)).thenReturn(false); + when(courseDifficultyFeedbackRepository.saveAndFlush(any(CourseDifficultyFeedback.class))) + .thenThrow(new DataIntegrityViolationException("not-null violation")); + + assertThatThrownBy(() -> hikingRecordService.createCourseDifficultyFeedback( + 1L, + 10L, + new CreateCourseDifficultyFeedbackRequest(DifficultyFeedbackType.SIMILAR) + )) + .isNotInstanceOfSatisfying(GeneralException.class, ex -> + assertThat(ex.getErrorStatus()) + .isEqualTo(ErrorStatus.COURSE_DIFFICULTY_FEEDBACK_ALREADY_EXISTS)); + }🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/test/java/com/semosan/api/domain/hiking/service/HikingRecordServiceTest.java` around lines 151 - 171, Add a new unit test in HikingRecordServiceTest that mirrors createCourseDifficultyFeedbackThrowsConflictWhenConcurrentDuplicateSaveOccurs but makes courseDifficultyFeedbackRepository.saveAndFlush(...) throw a DataIntegrityViolationException with a non-duplicate message (e.g., "foreign key constraint fails" or "not-null violation"); call hikingRecordService.createCourseDifficultyFeedback(...) and assert the thrown GeneralException's errorStatus is NOT ErrorStatus.COURSE_DIFFICULTY_FEEDBACK_ALREADY_EXISTS (use extracting("errorStatus").isNotEqualTo(...)); keep the same setup for userReader.findCompletedOnboardingUserById, hikingRecordRepository.findById, hikingMemberRepository.existsByHikingRecordAndUser and courseDifficultyFeedbackRepository.existsByHikingRecord_Id to locate the test logic near the existing createCourseDifficultyFeedback... test.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In
`@src/main/java/com/semosan/api/domain/hiking/entity/CourseDifficultyFeedback.java`:
- Around line 55-68: In CourseDifficultyFeedback.create add a defensive null
check for the course returned by hikingRecord.getCourse(): if course is null,
throw an IllegalArgumentException (or similar runtime exception) with a clear
message (e.g., "course must not be null") before calling course.getDifficulty();
update the create method in CourseDifficultyFeedback to validate hikingRecord
and course (referencing the create(...) method, CourseDifficultyFeedback class,
hikingRecord.getCourse(), and guideDifficulty/course.getDifficulty()) so the
entity enforces the non-null invariant.
In
`@src/main/java/com/semosan/api/domain/hiking/service/HikingRecordService.java`:
- Around line 105-109: In HikingRecordService.createCourseDifficultyFeedback,
narrow the catch for DataIntegrityViolationException by inspecting the nested
cause chain for org.hibernate.exception.ConstraintViolationException and only
map to ErrorStatus.COURSE_DIFFICULTY_FEEDBACK_ALREADY_EXISTS when the
constraintName equals "uk_course_difficulty_feedback_hiking_record" (the unique
constraint on hiking_record_id); for any other DataIntegrityViolationException
(or when the constraint name is different/missing) rethrow the original
exception (or wrap with a more general error) instead of always returning
COURSE_DIFFICULTY_FEEDBACK_ALREADY_EXISTS; update the concurrent duplicate save
test to assert the specific unique-constraint behavior rather than relying on a
generic DataIntegrityViolationException message.
---
Nitpick comments:
In
`@src/test/java/com/semosan/api/domain/hiking/service/HikingRecordServiceTest.java`:
- Around line 151-171: Add a new unit test in HikingRecordServiceTest that
mirrors
createCourseDifficultyFeedbackThrowsConflictWhenConcurrentDuplicateSaveOccurs
but makes courseDifficultyFeedbackRepository.saveAndFlush(...) throw a
DataIntegrityViolationException with a non-duplicate message (e.g., "foreign key
constraint fails" or "not-null violation"); call
hikingRecordService.createCourseDifficultyFeedback(...) and assert the thrown
GeneralException's errorStatus is NOT
ErrorStatus.COURSE_DIFFICULTY_FEEDBACK_ALREADY_EXISTS (use
extracting("errorStatus").isNotEqualTo(...)); keep the same setup for
userReader.findCompletedOnboardingUserById, hikingRecordRepository.findById,
hikingMemberRepository.existsByHikingRecordAndUser and
courseDifficultyFeedbackRepository.existsByHikingRecord_Id to locate the test
logic near the existing createCourseDifficultyFeedback... test.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: 46575288-f052-466d-9351-9b885a14cbd1
📒 Files selected for processing (13)
src/main/java/com/semosan/api/common/status/ErrorStatus.javasrc/main/java/com/semosan/api/common/status/SuccessStatus.javasrc/main/java/com/semosan/api/domain/hiking/controller/HikingRecordController.javasrc/main/java/com/semosan/api/domain/hiking/controller/docs/HikingRecordControllerDocs.javasrc/main/java/com/semosan/api/domain/hiking/dto/request/CreateCourseDifficultyFeedbackRequest.javasrc/main/java/com/semosan/api/domain/hiking/dto/response/CourseDifficultyFeedbackResponse.javasrc/main/java/com/semosan/api/domain/hiking/entity/CourseDifficultyFeedback.javasrc/main/java/com/semosan/api/domain/hiking/enums/DifficultyFeedbackType.javasrc/main/java/com/semosan/api/domain/hiking/repository/CourseDifficultyFeedbackRepository.javasrc/main/java/com/semosan/api/domain/hiking/repository/HikingRecordRepository.javasrc/main/java/com/semosan/api/domain/hiking/service/HikingRecordService.javasrc/main/resources/db/migration/V19__create_course_difficulty_feedbacks.sqlsrc/test/java/com/semosan/api/domain/hiking/service/HikingRecordServiceTest.java
🧾 요약
🔗 이슈
✨ 변경 내용
✅ 확인
Summary by CodeRabbit
New Features
Bug Fixes / Improvements